package cc.rengu.redp.system.service.impl;

import cc.rengu.redp.bizimpl.upmp.domain.UpmpOrganization;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpSysParamService;
import cc.rengu.redp.bizimpl.upmp.vo.UpmpUserInfoVO;
import cc.rengu.redp.bizimpl.utils.CommonUtils;
import cc.rengu.redp.bizimpl.utils.DateUtils;
import cc.rengu.redp.common.utils.DateUtil;
import cc.rengu.redp.common.utils.RedpUtil;
import cc.rengu.redp.system.dao.HolidaysMapper;
import cc.rengu.redp.system.domain.HolidayInfo;
import cc.rengu.redp.system.domain.Holidays;
import cc.rengu.redp.system.domain.UserRole;
import cc.rengu.redp.system.service.HolidaysService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author qiujunning
 */
@Slf4j
@Service
@DS("csmc")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class HolidaysServiceImpl extends ServiceImpl<HolidaysMapper, HolidayInfo> implements HolidaysService {

    @Autowired
    private HolidaysMapper holidaysMapper;
    @Autowired
    private IUpmpSysParamService upmpSysParamService;
    /**
     * 设置调班日期
     * @param dateStr
     * @throws Exception
     */
    @Override
    public void updatePubHolidays(String dateStr) throws Exception {
        String lastUpddt = DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
        String auditTime = DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
        //先查询
        List<HolidayInfo> holidayInfos = (this.list(new LambdaQueryWrapper<HolidayInfo>()
                .eq(HolidayInfo::getBatchDate, dateStr.replace("-", ""))
        ));
        HolidayInfo holidayinfo = new HolidayInfo();
        holidayinfo.setBatchDate(dateStr.replace("-", ""));
        holidayinfo.setOprStatus("01");
        holidayinfo.setAuditStatus("02");
        holidayinfo.setCreateTime(lastUpddt);
        holidayinfo.setAuditTime(auditTime);
        UpmpUserInfoVO user = CommonUtils.getCurrentUser(upmpSysParamService);
        holidayinfo.setOprId(user.getLoginId());
        if (holidayInfos != null && holidayInfos.size() > 0){
            for (HolidayInfo item: holidayInfos) {
                if (item.getHolidayFlag().equals("N")) {
                    holidayinfo.setHolidayFlag("Y");
                } else {
                    holidayinfo.setHolidayFlag("N");
                }
            }
            QueryWrapper<HolidayInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("batch_date", dateStr.replace("-", ""));
            holidaysMapper.update(holidayinfo,queryWrapper);
        }else {
            LocalDate localDate = LocalDate.parse(dateStr);
            HolidayInfo normalHoliday = getNormalHoliday(localDate, dateStr);
            if (normalHoliday.getHolidayFlag().equals("N")){
                holidayinfo.setHolidayFlag("Y");
            }else {
                holidayinfo.setHolidayFlag("N");
            }
            holidaysMapper.insert(holidayinfo);
        }
    }

    /**
     * 获取所在月的全部节假日信息
     * @return List<Holidays>
     */
    @Override
    public List<HolidayInfo> getHolidaysByDate(String currDate) {
        LocalDate localDate = LocalDate.parse(currDate);
        int currYear = localDate.getYear();
        int currMonth = localDate.getMonth().getValue();
        //获取前一个月的时间
        LocalDate localDateBefore = localDate.minusMonths(1); //获取前一个月的时间
        String beforeYearMonth = localDateBefore.toString().replace("-", "");
        String  beforeMonth= beforeYearMonth.substring(0, 6);//截取前一个月的年月

        //获取下一个月
        LocalDate localDateAfter = localDate.plusMonths(1);//获取后一个月的时间
        String afterYearMonth = localDateAfter.toString().replace("-", "");
        String  afterMonth= afterYearMonth.substring(0, 6);//截取后一月的年月
        //查询当前月假期
        List<HolidayInfo> holidayInfo = (this.list(new LambdaQueryWrapper<HolidayInfo>()
                .eq(HolidayInfo::getHolidayFlag,"Y")
                .likeRight(HolidayInfo::getBatchDate, currDate.replace("-", "").substring(0, 6))
        ));
        holidayInfo.addAll(this.list(new LambdaQueryWrapper<HolidayInfo>()
                .eq(HolidayInfo::getHolidayFlag,"Y")
                .likeRight(HolidayInfo::getBatchDate, beforeMonth)
        ));
        holidayInfo.addAll(this.list(new LambdaQueryWrapper<HolidayInfo>()
                .eq(HolidayInfo::getHolidayFlag,"Y")
                .likeRight(HolidayInfo::getBatchDate, afterMonth)
        ));
        Map<String, HolidayInfo> holidaysMap = new HashMap<>();
        for (HolidayInfo item : holidayInfo){
            holidaysMap.put(item.getBatchDate(), item);
        }
        System.out.println(holidaysMap.get("20220609"));
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DateUtil.DATE_PATTERN);

        //遍历月份，补全缺失数据
        for (int day = 1; day <= localDate.lengthOfMonth(); day++) {
            LocalDate ld = LocalDate.of(currYear, currMonth, day);
            String holidayFmtStr = ld.format(dtf);
            if (holidaysMap.get(holidayFmtStr) == null) {
                holidayInfo.add(getNormalHoliday(ld, holidayFmtStr));
            }
        }

        //获取前一月的部分数据（按完整周补全）
        LocalDate ldFirstOfMonth = LocalDate.of(currYear, currMonth, 1);
        for (int cnt = ldFirstOfMonth.getDayOfWeek().getValue(); cnt > 1; cnt--) {
            LocalDate ld = ldFirstOfMonth.minusDays(cnt - 1);
            String holidayFmtStr = ld.format(dtf);
            if (holidaysMap.get(holidayFmtStr) == null) {
                holidayInfo.add(getNormalHoliday(ld, holidayFmtStr));
            }
        }

        //获取后一月的部分数据（按完整周补全）
        LocalDate ldLastOfMonth = LocalDate.of(currYear, currMonth, localDate.lengthOfMonth());
        int daysOfAfterMonth = ldLastOfMonth.getDayOfWeek().getValue();
        for (int cnt = daysOfAfterMonth; cnt < 7; cnt++) {
            LocalDate ld = ldLastOfMonth.plusDays(7 - cnt);
            String holidayFmtStr = ld.format(dtf);
            if (holidaysMap.get(holidayFmtStr) == null) {
                holidayInfo.add(getNormalHoliday(ld, holidayFmtStr));
            }
        }

        //若当月不满6周，则补全到6周
        WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY,1);
        int weekNum = ldLastOfMonth.get(weekFields.weekOfMonth());
        if (weekNum < 6) {
            for (int cnt = 0; cnt < 7 * (6 - weekNum); cnt++) {
                LocalDate ld = ldLastOfMonth.plusDays(7 - daysOfAfterMonth + 1 + cnt);
                String holidayFmtStr = ld.format(dtf);
                if (holidaysMap.get(holidayFmtStr) == null) {
                    holidayInfo.add(getNormalHoliday(ld, holidayFmtStr));
                }
            }
        }
        return holidayInfo;
    }

    /**
     * 构建普通节假日信息
     * @param ld  localDate日期
     * @param holidayFmtStr 已格式化的localDate日期
     * @return
     */
    private HolidayInfo getNormalHoliday(LocalDate ld, String holidayFmtStr){
        HolidayInfo holidayInfo = new HolidayInfo();
        List<HolidayInfo> holidayInfos = (this.list(new LambdaQueryWrapper<HolidayInfo>()
                .eq(HolidayInfo::getBatchDate, holidayFmtStr.replace("-", ""))
        ));
        if (holidayInfos != null && holidayInfos.size() > 0) {
            for (HolidayInfo item : holidayInfos) {
                holidayInfo.setBatchDate(holidayFmtStr);
                holidayInfo.setHolidayFlag(item.getHolidayFlag());
                return holidayInfo;
            }
        }
            holidayInfo.setBatchDate(holidayFmtStr);
            if (ld.getDayOfWeek().getValue() == 6 || ld.getDayOfWeek().getValue() == 7) {
                holidayInfo.setHolidayFlag("Y");
            } else {
                holidayInfo.setHolidayFlag("N");
            }
            return holidayInfo;
    }
}